package com.bee.common.core.exception;

import java.util.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.method.HandlerMethod;

import com.baomidou.mybatisplus.toolkit.Sequence;
import com.bee.common.core.log.persistence.entity.LogException;
import com.bee.common.core.log.service.ILogExceptionService;
import com.bee.common.core.result.Result;
import com.bee.common.core.constant.Constant;

/**
 * Created by liekkas on 2017-8-1.
 * 全局服务异常拦截
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    private final static Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @Autowired
    private ILogExceptionService logExceptionService;

    /**
     * 拦截ApplicationException异常
     *
     * @param req
     * @param resp
     * @param handlerMethod
     * @param e
     * @return
     */

    @ExceptionHandler(ApplicationException.class)
    public void ApplicationException(HttpServletRequest req, HttpServletResponse resp, HandlerMethod handlerMethod, ApplicationException e) {
        saveException(handlerMethod,e);
    }

    @ResponseBody
    @ExceptionHandler(BusinessException.class)
    public Result BusinessException(HttpServletRequest req, HttpServletResponse resp, HandlerMethod handlerMethod, BusinessException e) {
        saveException(handlerMethod, e);
        return Result.fail(e.getResult().getMsg());
    }


    //验证异常
    @ResponseBody
    @ExceptionHandler({ConstraintViolationException.class})
    public Result ConstraintViolationException(HandlerMethod handlerMethod, ConstraintViolationException e) {
        saveException(handlerMethod, e);
        Set<ConstraintViolation<?>> constraintViolations= e.getConstraintViolations();
        if(constraintViolations!=null&&constraintViolations.size()>0){
            ConstraintViolation constraintViolation=null;
            Iterator iterator=constraintViolations.iterator();
            int count=0;
            while (iterator.hasNext()){
                count++;
                ConstraintViolation temp= (ConstraintViolation) iterator.next();
                if(count==1)
                    constraintViolation=temp;
            }
            return Result.fail(constraintViolation.getMessageTemplate());
        }
        return Result.fail();
    }


    /**
     * 拦截Exception异常
     * @param handlerMethod
     * @param e
     * @return
     */
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result handleException(HandlerMethod handlerMethod, Exception e) {
        saveException(handlerMethod,e);
        return Result.fail(e.getMessage());
    }


    /**
     * 获取栈信息
     *
     * @param e
     * @return
     */
    public static Map<String, Object> getTraceInfo(Exception e) {

        Map<String, Object> map = new HashMap<>();

        StringBuffer stringBuffer = new StringBuffer();
        String message = e.toString();
        if (message.lastIndexOf(":") != -1) {
            message = message.substring(0, message.lastIndexOf(":"));
        }
        stringBuffer.append(message + "\r\n");

        //栈信息处理
        StackTraceElement[] stacks = e.getStackTrace();
        for (int i = 0; i < stacks.length; i++) {
            stringBuffer.append("\tat " + stacks[i] + "\r\n");
        }
        int lineNumber = stacks.length > 0 ? stacks[0].getLineNumber() : 0;
        map.put("line", lineNumber);
        map.put("stackMessage", stringBuffer.toString());
        LOGGER.error(e.getMessage());
        return map;
    }

    /**
     * 保存栈信息
     *
     * @param handler
     * @param ex
     */
    public void saveException(Object handler, Exception ex) {
        ex.printStackTrace();

        //异常信息初始化
        String className = ((HandlerMethod) handler).getBean().getClass().getName();
        String methodName = ((HandlerMethod) handler).getMethod().getName();

        Map map = getTraceInfo(ex);
        Long rowNumber = Long.valueOf(map.get("line").toString());
        String stackMessage = map.get("stackMessage").toString();
        String logLevel = null;
        String logMessage = null;

        if(ex instanceof ApplicationException){
            logLevel = ((ApplicationException)ex).getExceptionLevel();
            logMessage = ((ApplicationException)ex).getResult().getMsg();
        }else{
            logLevel = Constant.LOG_LEVEL_LOW;
            logMessage = ex.getMessage();
        }

        //构建日志实体
        LogException logException = new LogException();
        logException.setId(new Sequence(0, 0).nextId())
                    .setClassName(className)
                    .setLogType(ex.toString())
                    .setLogLevel(logLevel)
                    .setCreateDate(new Date())
                    .setLogMessage(logMessage)
                    .setMethodName(methodName)
                    .setRowNumber(rowNumber)
                    .setStackTrace(stackMessage)
                    .setThreadName(Thread.currentThread().getName());

        //保存
        logExceptionService.addLogExceptionAsyn(logException);
    }
}
